package cn.funnymap.lgis.utils;

import cn.funnymap.lgis.response.exception.common.ParamValidationException;

import javax.validation.ValidationException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 日期工具类
 *
 * @author jiaoxn
 */
public class DateUtil {
    private DateUtil() {}

    private static final String DATA_STR_FORMAT = "yyyy-MM-dd";
    private static final String DATE_TIME_STR_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * 日期转换，字符串（yyyy-MM-dd格式）转Date
     *
     * @param dateAsStr 字符串格式的日期
     * @return Date 对象
     */
    public static Date str2Date(String dateAsStr) throws ParseException {
        return strToDate(dateAsStr, DATA_STR_FORMAT);
    }

    /**
     * 日期转换，字符串转Date，支持自定义日期格式
     *
     * @param dateAsStr 字符串格式的日期
     * @param format 字符串格式
     * @return Date 对象
     */
    public static Date strToDate(String dateAsStr, String format) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.parse(dateAsStr);
    }

    /**
     * 日期转换，Date转字符串，按照yyyy-MM-dd格式
     *
     * @param date 日期
     * @return 字符串格式的日期
     */
    public static String date2str(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATA_STR_FORMAT);
        return simpleDateFormat.format(date);
    }

    /**
     * 日期转换，Date转字符串，按照yyyy-MM-dd格式
     *
     * @param date 日期
     * @param format 字符串格式
     * @return 字符串格式的日期
     */
    public static String date2str(Date date, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }

    /**
     * 时间转换，字符串转LocalDateTime，按照yyyy-MM-dd HH:mm:ss格式
     * @param dateTimeAsStr 字符串格式的日期时间
     * @return LocalDateTime
     */
    public static LocalDateTime str2LocalDateTime(String dateTimeAsStr) {
        return str2LocalDateTime(dateTimeAsStr, DATE_TIME_STR_FORMAT);
    }

    /**
     * 时间转换，字符串转LocalDateTime，支持自定义格式
     * @param dateTimeAsStr 字符串格式的日期时间
     * @return LocalDateTime
     */
    public static LocalDateTime str2LocalDateTime(String dateTimeAsStr, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return LocalDateTime.parse(dateTimeAsStr, formatter);
    }

    /**
     * 时间转换，LocalDateTime转字符串，按照yyyy-MM-dd HH:mm:ss格式
     * @param localDateTime 时间
     * @return 字符串格式的日期时间
     */
    public static String localDateTime2Str(LocalDateTime localDateTime) {
        return localDateTime2Str(localDateTime, DATE_TIME_STR_FORMAT);
    }

    /**
     * 时间转换，LocalDateTime转字符串，支持自定义格式
     * @param localDateTime 时间
     * @param format 时间格式
     * @return 字符串格式的日期时间
     */
    public static String localDateTime2Str(LocalDateTime localDateTime, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(formatter);
    }

    public static List<Date> dateRangeDto2DateList(String from, String to) throws ParseException {
        if (from == null || from.isEmpty() || to == null || to.isEmpty()) {
            return new ArrayList<>();
        }

        List<Date> dateList = new ArrayList<>();
        dateList.add(DateUtil.str2Date(from));
        dateList.add(DateUtil.str2Date(to));

        return dateList;
    }

    /**
     * 使用正则表达式校验起始日期和截止日期的格式是否为 YYYY-MM-DD
     *
     * @param from 起始日期
     * @param to 截止日期
     */
    public static void dateFormatValidation(String from, String to) {
        // 日期正则匹配规则：YYYY-MM-DD
        String validationRegRule = "\\d{4}-\\d{2}-\\d{2}";

        Pattern pattern = Pattern.compile(validationRegRule);

        if (!pattern.matcher(from).matches() || !pattern.matcher(to).matches()) {
            throw new ValidationException("起始日期和截止日期格式不正确，请检查日期格式是否为 YYYY-MM-DD");
        }
    }

    /**
     * 起始日期和截止日期的先后顺序验证
     *
     * @param from 起始日期
     * @param to 截止日期
     */
    public static void sequentialValidation(String from, String to) throws ParseException {
        Date fromDate = DateUtil.str2Date(from);
        Date toDate = DateUtil.str2Date(to);

        if (fromDate.compareTo(toDate) > 0) {
            throw new ParamValidationException("截止日期不能早于起始日期");
        }
    }

    /**
     * LocalDateTime转Date，使用系统默认时区
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * LocalDateTime转Date
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime, ZoneId zoneId) {
        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取与当前日志相隔几天后的日期，如果是负数，表示几天前的日期
     *
     * @param value 整数值，可以是负数
     * @return 日期
     */
    public static Date plus(Integer value) {
        return Date.from(LocalDateTime.now().plusDays(value).atZone(ZoneId.systemDefault()).toInstant());
    }
}
